經過一整天的奮鬥,終於跟React稍微熟了一點
首先建一個apiUtil.js
我打算把跟後端相關的方法都集中在這邊做管理
先從登入開始
這邊就是拿使用者輸入的email、登入帳號、密碼,用axios丟到後端登入api
import axios from "axios";
const userRequest = axios.create({
baseURL: 'http://localhost:8080',
headers: { 'Content-Type': 'application/json' },
})
export const login = (email,userAccount, userPassword) => {
return userRequest.post("/demo/api/v1/user/login",
JSON.stringify({
email,
userAccount,
userPassword,})
).then((res) => res.data).catch((err)=>err.toString());
};
再來,建立一個Login.js,這支是拿來放登入頁面的component
import React, { useState } from 'react';
import { login } from "../util/auth";
import { setAuthToken } from "../util/auth";
import { useHistory } from "react-router-dom";
const Login =() => {
const [useremail, setUseremail] = useState("");
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [errorMessage, setErrorMessage] = useState("");
const [loading, setLoading] = useState(false);
const handleLogin = (e) => {
setLoading(true);
setErrorMessage(null);
login(useremail,username, password).then((data) => {
if (data.token ==null) {
setLoading(false);
return setErrorMessage(data.status);
}
setLoading(false);
});
};
const handleUseremail = (e) => {
setUseremail(e.target.value);
};
const handleUsername = (e) => {
setUsername(e.target.value);
};
const handlePassword = (e) => {
setPassword(e.target.value);
};
return(
<div className="hero min-h-screen bg-base-200">
<div className="flex-col justify-center hero-content lg:flex-row">
<div className="text-center lg:text-left">
<h1 className="mb-5 text-5xl font-bold">
IT鐵人賽
</h1>
<p className="mb-5">
30天全端挑戰!React+Spring Boot+Mongo DB 串接永豐API 打造金融網站
</p>
</div>
<div className="card flex-shrink-0 w-full max-w-sm shadow-2xl bg-base-100">
<div className="card-body">
<div className="form-control">
<label className="label">
<span className="label-text">信箱</span>
</label>
<input type="text" placeholder="email" className="input input-bordered" value={useremail} onChange={handleUseremail}/>
</div>
<div className="form-control">
<label className="label">
<span className="label-text">帳號</span>
</label>
<input type="text" placeholder="account" className="input input-bordered" value={username} onChange={handleUsername}/>
</div>
<div className="form-control">
<label className="label">
<span className="label-text">密碼</span>
</label>
<input placeholder="password" className="input input-bordered" type="password" value={password} onChange={handlePassword}/>
<label className="label">
</label>
</div>
{errorMessage && <><small style={{ color: 'red' }}>{errorMessage}</small><br /></>}<br/>
<div className="form-control mt-6">
<input type="button" className="btn btn-primary" value={loading ? '登入中...' : '登入'} onClick={handleLogin} disabled={loading} />
</div>
</div>
</div>
</div>
</div>
)
}
export default Login
這邊就是把使用者輸入的值做綁定,輸入完之後,如果按登入就會觸發事件把資料藉由前面在apiUtil寫的方法帶到api
因為我在登入api有做調整,改成回json格式,
登入成功的話會帶status跟token兩個值
失敗的話就只會帶status,
所以我在這邊以data.token是否存在來判斷有沒有登入成功,
登入失敗的話就會把status秀出來在頁面上
Login.js寫好之後,就拿它來取代原本在index.js的<APP/>
在index.js引入import Login from './components/Login'
之後
就可以把<APP/>
換成<Login/>
這麼一來React的預設畫面就會被換成剛剛寫好的登入頁了
寫完之後就來試試
又遇到了熟悉的CORS問題
這裡要回到Spring Boot後端
上次新增的WebSecurityConfig.java去增加CORS的設定
允許localhost:3000連到這個Spring Boot的後端取資料
import java.util.Arrays;
import com.rei1997.vault.util.filter.AuthorizationCheckFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import static org.springframework.security.config.Customizer.withDefaults;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(new AuthorizationCheckFilter(), BasicAuthenticationFilter.class);
http.cors(withDefaults());//增加這行
}
//增加這個bean
@Bean
CorsConfigurationSource corsConfigurationSource() {
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(
Arrays.asList("http://localhost:3000"));
configuration.setAllowedMethods(
Arrays.asList("GET", "PUT", "POST", "PATCH", "DELETE", "OPTIONS"));
configuration.setAllowedHeaders(
Arrays.asList("Authorization", "Cache-Control", "Content-Type"));
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
再來試試,
故意輸入錯誤的密碼,因為登入成功後的動作我還沒寫好
頁面顯示0003
沒錯,就是密碼錯誤
測試成功,接下來就試著把登入成功後得到的token存到cookie或者localstorage裡面
然後要在每次對後端api發request時帶上著個token以通過驗證